#include <config.h>
#include "asm.h"

#ifdef DO_MMX_ASM

/*\ 
|*| MMX assembly blending routines, with colour modding, for Imlib2
|*| Written by Willem Monsuwe <willem@stack.nl>
|*|
|*| Special (hairy) constructs are only commented on first use.
\*/

/*\ All functions have the same calling convention:
|*|  PR_(imlib_mmx_<op>_rgba_to_rgb[A]_cmod(void *src, int sw, void *dst, int dw,
|*|					  int w, int h, ImlibColorModifier *cm)
\*/

#define src	8(%ebp)
#define sw	12(%ebp)
#define dst	16(%ebp)
#define dw	20(%ebp)
#define w	24(%ebp)
#define h	28(%ebp)
#define cm	32(%ebp)

/*\ Cmod tables, from %ebx \*/
#define rmap(x)		(%ebx, x)
#define gmap(x)		0x100(%ebx, x)
#define bmap(x)		0x200(%ebx, x)
#define amap(x)		0x300(%ebx, x)
#define amap_ff		0x3ff(%ebx)

.text
	.align 8
FN_(imlib_mmx_blend_rgba_to_rgb_cmod)
FN_(imlib_mmx_blend_rgba_to_rgba_cmod)
FN_(imlib_mmx_blend_rgb_to_rgb_cmod)
FN_(imlib_mmx_blend_rgb_to_rgba_cmod)

FN_(imlib_mmx_copy_rgba_to_rgb_cmod)
FN_(imlib_mmx_copy_rgba_to_rgba_cmod)
FN_(imlib_mmx_copy_rgb_to_rgba_cmod)

FN_(imlib_mmx_add_blend_rgba_to_rgb_cmod)
FN_(imlib_mmx_add_blend_rgba_to_rgba_cmod)
FN_(imlib_mmx_add_blend_rgb_to_rgb_cmod)
FN_(imlib_mmx_add_blend_rgb_to_rgba_cmod)

FN_(imlib_mmx_add_copy_rgba_to_rgb_cmod)
FN_(imlib_mmx_add_copy_rgba_to_rgba_cmod)
FN_(imlib_mmx_add_copy_rgb_to_rgba_cmod)

FN_(imlib_mmx_subtract_blend_rgba_to_rgb_cmod)
FN_(imlib_mmx_subtract_blend_rgba_to_rgba_cmod)
FN_(imlib_mmx_subtract_blend_rgb_to_rgb_cmod)
FN_(imlib_mmx_subtract_blend_rgb_to_rgba_cmod)

FN_(imlib_mmx_subtract_copy_rgba_to_rgb_cmod)
FN_(imlib_mmx_subtract_copy_rgba_to_rgba_cmod)
FN_(imlib_mmx_subtract_copy_rgb_to_rgba_cmod)

FN_(imlib_mmx_reshade_blend_rgba_to_rgb_cmod)
FN_(imlib_mmx_reshade_blend_rgba_to_rgba_cmod)
FN_(imlib_mmx_reshade_blend_rgb_to_rgb_cmod)
FN_(imlib_mmx_reshade_blend_rgb_to_rgba_cmod)

FN_(imlib_mmx_reshade_copy_rgba_to_rgb_cmod)
FN_(imlib_mmx_reshade_copy_rgba_to_rgba_cmod)
FN_(imlib_mmx_reshade_copy_rgb_to_rgba_cmod)

#include "asm_loadimmq.S"
	
/*\ MMX register use:
|*| %mm1 = Source value
|*| %mm2 = Destination value
|*| %mm3 = Alpha value
|*| %mm4 = 0
|*| %mm5-%mm6 = masks
\*/

/*\ Common code \*/
/*\ Set MMX mode, save registers, load common parameters \*/
#define ENTER				\
	pushl %ebp			;\
	movl  %esp, %ebp		;\
	pushl %ebx			;\
	pushl %ecx			;\
	pushl %edx			;\
	pushl %edi			;\
	pushl %esi			;\
	movl cm,  %ebx			;\
	movl src, %esi			;\
	movl dst, %edi			;\
	movl w,   %ecx			;\
	leal (%esi, %ecx, 4), %esi	;\
	leal (%edi, %ecx, 4), %edi	;\
	negl %ecx			;\
	jz 9f				;\
	movl h,   %edx			;\
	decl  %edx			;\
	jz 9f				;\

#define LOOP_START		\
8:				;\
	movl w, %ecx		;\
	negl %ecx

#define LOOP_END			\
	movl sw, %ecx			;\
	leal (%esi, %ecx, 4), %esi	;\
	movl dw, %ecx			;\
	leal (%edi, %ecx, 4), %edi	;\
	decl %edx			;\
	jns 8b


/*\ Unset MMX mode, reset registers, return \*/
#define LEAVE			\
9:				;\
	emms			;\
	popl %esi		;\
	popl %edi		;\
	popl %edx		;\
	popl %ecx		;\
	popl %ebx		;\
	movl %ebp, %esp		;\
	popl %ebp		;\
	ret


/*\ Load one value, colourmod it, and put it in %mm1 \*/
#define LOAD1_CMOD			\
	movzbl 3(%esi, %ecx, 4), %eax	;\
	movzbl amap(%eax), %eax		;\
	movd %eax, %mm1			;\
	movzbl 2(%esi, %ecx, 4), %eax	;\
	psllq $8, %mm1			;\
	movzbl rmap(%eax), %eax		;\
	movd %eax, %mm0			;\
	movzbl 1(%esi, %ecx, 4), %eax	;\
	por %mm0, %mm1			;\
	movzbl gmap(%eax), %eax		;\
	psllq $8, %mm1			;\
	movd %eax, %mm0			;\
	movzbl (%esi, %ecx, 4), %eax	;\
	por %mm0, %mm1			;\
	movzbl bmap(%eax), %eax		;\
	psllq $8, %mm1			;\
	movd %eax, %mm0			;\
	por %mm0, %mm1


/*\ Load two values, colourmod them, and put them in %mm1 \*/
#define LOAD2_CMOD			\
	movzbl 7(%esi, %ecx, 4), %eax	;\
	movzbl amap(%eax), %eax		;\
	movd %eax, %mm1			;\
	movzbl 6(%esi, %ecx, 4), %eax	;\
	psllq $8, %mm1			;\
	movzbl rmap(%eax), %eax		;\
	movd %eax, %mm0			;\
	movzbl 5(%esi, %ecx, 4), %eax	;\
	por %mm0, %mm1			;\
	movzbl gmap(%eax), %eax		;\
	psllq $8, %mm1			;\
	movd %eax, %mm0			;\
	movzbl 4(%esi, %ecx, 4), %eax	;\
	por %mm0, %mm1			;\
	movzbl bmap(%eax), %eax		;\
	psllq $8, %mm1			;\
	movd %eax, %mm0			;\
	movzbl 3(%esi, %ecx, 4), %eax	;\
	por %mm0, %mm1			;\
	movzbl amap(%eax), %eax		;\
	psllq $8, %mm1			;\
	movd %eax, %mm0			;\
	movzbl 2(%esi, %ecx, 4), %eax	;\
	por %mm0, %mm1			;\
	movzbl rmap(%eax), %eax		;\
	psllq $8, %mm1			;\
	movd %eax, %mm0			;\
	movzbl 1(%esi, %ecx, 4), %eax	;\
	por %mm0, %mm1			;\
	movzbl gmap(%eax), %eax		;\
	psllq $8, %mm1			;\
	movd %eax, %mm0			;\
	movzbl (%esi, %ecx, 4), %eax	;\
	por %mm0, %mm1			;\
	movzbl bmap(%eax), %eax		;\
	psllq $8, %mm1			;\
	movd %eax, %mm0			;\
	por %mm0, %mm1


/*\ Load one value, alpha 0xff, colourmod it, and put it in %mm1 \*/
#define LOAD1_CMOD_AFF			\
	movzbl amap_ff, %eax		;\
	movd %eax, %mm1			;\
	movzbl 2(%esi, %ecx, 4), %eax	;\
	psllq $8, %mm1			;\
	movzbl rmap(%eax), %eax		;\
	movd %eax, %mm0			;\
	movzbl 1(%esi, %ecx, 4), %eax	;\
	por %mm0, %mm1			;\
	movzbl gmap(%eax), %eax		;\
	psllq $8, %mm1			;\
	movd %eax, %mm0			;\
	movzbl (%esi, %ecx, 4), %eax	;\
	por %mm0, %mm1			;\
	movzbl bmap(%eax), %eax		;\
	psllq $8, %mm1			;\
	movd %eax, %mm0			;\
	por %mm0, %mm1


/*\ Load two values, alpha 0xff, colourmod them, and put them in %mm1 \*/
#define LOAD2_CMOD_AFF			\
	movzbl amap_ff, %eax		;\
	movd %eax, %mm1			;\
	movzbl 6(%esi, %ecx, 4), %eax	;\
	psllq $8, %mm1			;\
	movzbl rmap(%eax), %eax		;\
	movd %eax, %mm0			;\
	movzbl 5(%esi, %ecx, 4), %eax	;\
	por %mm0, %mm1			;\
	movzbl gmap(%eax), %eax		;\
	psllq $8, %mm1			;\
	movd %eax, %mm0			;\
	movzbl 4(%esi, %ecx, 4), %eax	;\
	por %mm0, %mm1			;\
	movzbl bmap(%eax), %eax		;\
	psllq $8, %mm1			;\
	movd %eax, %mm0			;\
	por %mm0, %mm1			;\
	movzbl amap_ff, %eax		;\
	psllq $8, %mm1			;\
	movd %eax, %mm0			;\
	movzbl 2(%esi, %ecx, 4), %eax	;\
	por %mm0, %mm1			;\
	movzbl rmap(%eax), %eax		;\
	psllq $8, %mm1			;\
	movd %eax, %mm0			;\
	movzbl 1(%esi, %ecx, 4), %eax	;\
	por %mm0, %mm1			;\
	movzbl gmap(%eax), %eax		;\
	psllq $8, %mm1			;\
	movd %eax, %mm0			;\
	movzbl (%esi, %ecx, 4), %eax	;\
	por %mm0, %mm1			;\
	movzbl bmap(%eax), %eax		;\
	psllq $8, %mm1			;\
	movd %eax, %mm0			;\
	por %mm0, %mm1


/*\ Load one value, colourmod it, alpha 0, and put it in %mm1 \*/
#define LOAD1_CMOD_A00			\
	movzbl 2(%esi, %ecx, 4), %eax	;\
	movzbl rmap(%eax), %eax		;\
	movd %eax, %mm1			;\
	movzbl 1(%esi, %ecx, 4), %eax	;\
	psllq $8, %mm1			;\
	movzbl gmap(%eax), %eax		;\
	movd %eax, %mm0			;\
	movzbl (%esi, %ecx, 4), %eax	;\
	por %mm0, %mm1			;\
	movzbl bmap(%eax), %eax		;\
	psllq $8, %mm1			;\
	movd %eax, %mm0			;\
	por %mm0, %mm1


/*\ Load two values, colourmod them, alpha 0, and put them in %mm1 \*/
#define LOAD2_CMOD_A00			\
	movzbl 6(%esi, %ecx, 4), %eax	;\
	movzbl rmap(%eax), %eax		;\
	movd %eax, %mm1			;\
	movzbl 5(%esi, %ecx, 4), %eax	;\
	psllq $8, %mm1			;\
	movzbl gmap(%eax), %eax		;\
	movd %eax, %mm0			;\
	movzbl 4(%esi, %ecx, 4), %eax	;\
	por %mm0, %mm1			;\
	movzbl bmap(%eax), %eax		;\
	psllq $8, %mm1			;\
	movd %eax, %mm0			;\
	movzbl 2(%esi, %ecx, 4), %eax	;\
	por %mm0, %mm1			;\
	movzbl rmap(%eax), %eax		;\
	psllq $16, %mm1			;\
	movd %eax, %mm0			;\
	movzbl 1(%esi, %ecx, 4), %eax	;\
	por %mm0, %mm1			;\
	movzbl gmap(%eax), %eax		;\
	psllq $8, %mm1			;\
	movd %eax, %mm0			;\
	movzbl (%esi, %ecx, 4), %eax	;\
	por %mm0, %mm1			;\
	movzbl bmap(%eax), %eax		;\
	psllq $8, %mm1			;\
	movd %eax, %mm0			;\
	por %mm0, %mm1



PR_(imlib_mmx_blend_rgba_to_rgb_cmod):
	ENTER

	pxor %mm4, %mm4
	LOAD_IMMQ(c1, %mm5)
	CLEANUP_IMMQ_LOADS(1)

	LOOP_START
1:
	/*\ Load source and destination \*/
	LOAD1_CMOD
	movd (%edi, %ecx, 4), %mm2

	/*\ Get alpha from source and unpack/copy to eight bytes
	|*|  which are treated as four words.
	|*| Result ranges from [0, 0x7fff), and is mapped to
	|*|  point value in [0.0, 1.0) by using the high word
	|*|  of the 16->32 multiplications.
	|*| (Because we want the unsigned value we shift one bit,
	|*|  and also shift the other factor to compensate.)
	|*| Magic to get the fourth byte: lhh
	\*/
	movq %mm1, %mm3
	punpcklbw %mm3, %mm3
	punpckhwd %mm3, %mm3
	punpckhdq %mm3, %mm3
	psrlw $1, %mm3

	/*\ Make the alpha value that gets multiplied to the
	|*|  alpha channels 0, so the resulting alpha value is
	|*|  the destination alpha value.
	\*/
	psrlq $16, %mm3

	/*\ Unpack source and destination, bytes to words \*/
	punpcklbw %mm4, %mm1
	punpcklbw %mm4, %mm2

	/*\ d = d + (a * ((s - d) + 0.5)) \*/
	psubw %mm2, %mm1
	psllw $1, %mm1
	paddw %mm5, %mm1	/*\ Roundoff \*/
	pmulhw %mm3, %mm1
	paddw %mm1, %mm2

	/*\ Pack into lower 4 bytes and save \*/
	packuswb %mm4, %mm2
	movd %mm2, (%edi, %ecx, 4)

	incl %ecx
	js 1b

	LOOP_END
	LEAVE

SIZE(imlib_mmx_blend_rgba_to_rgb_cmod)

PR_(imlib_mmx_blend_rgba_to_rgba_cmod):
	ENTER

	pxor %mm4, %mm4
	LOAD_IMMQ(m0X000000, %mm5)
	LOAD_IMMQ(m00XXXXXX, %mm6)
	LOAD_IMMQ(c1, %mm7)
	CLEANUP_IMMQ_LOADS(3)

	LOOP_START
1:
	/*\ Load source and destination \*/
	LOAD1_CMOD
	movd (%edi, %ecx, 4), %mm2

	/*\ Get alpha from source and target, a = src + (255 - dest) \*/
	movq %mm2, %mm3
	pxor %mm6, %mm3
	paddusb %mm1, %mm3
	/*\ Unpack/copy to eight bytes \*/
	punpcklbw %mm3, %mm3
	punpckhwd %mm3, %mm3
	punpckhdq %mm3, %mm3
	psrlw $1, %mm3

	/*\ Unpack source and destination, bytes to words \*/
	punpcklbw %mm4, %mm1
	punpcklbw %mm4, %mm2

	/*\ Separate alpha channel \*/
	movq %mm1, %mm0
	pand %mm5, %mm0

	/*\ d = d + (a * ((s - d) + 0.5)) \*/
	psubw %mm2, %mm1
	psllw $1, %mm1
	paddw %mm7, %mm1	/*\ Roundoff \*/
	pmulhw %mm3, %mm1

	/*\ Replace alpha channel with separated out version in mm0 and add \*/
	pand %mm6, %mm1
	por %mm0, %mm1
	paddw %mm1, %mm2

	/*\ Pack into lower 4 bytes and save \*/
	packuswb %mm4, %mm2
	movd %mm2, (%edi, %ecx, 4)

	incl %ecx
	js 1b

	LOOP_END
	LEAVE

SIZE(imlib_mmx_blend_rgba_to_rgba_cmod)

PR_(imlib_mmx_blend_rgb_to_rgb_cmod):
	ENTER

	pxor %mm4, %mm4
	LOAD_IMMQ(c1, %mm5)
	CLEANUP_IMMQ_LOADS(1)

	/*\ Load alpha beforehand, as it's always amap(0xff) \*/
	movzbl amap_ff, %eax
	movd %eax, %mm3
	punpcklbw %mm3, %mm3
	punpcklwd %mm3, %mm3
	punpckldq %mm3, %mm3
	psrlw $1, %mm3
	psrlq $16, %mm3

	LOOP_START
1:
	/*\ Load source and destination \*/
	LOAD1_CMOD_A00
	movd (%edi, %ecx, 4), %mm2

	/*\ Unpack source and destination, bytes to words \*/
	punpcklbw %mm4, %mm1
	punpcklbw %mm4, %mm2

	/*\ d = d + (a * ((s - d) + 0.5)) \*/
	psubw %mm2, %mm1
	psllw $1, %mm1
	paddw %mm5, %mm1	/*\ Roundoff \*/
	pmulhw %mm3, %mm1
	paddw %mm1, %mm2

	/*\ Pack into lower 4 bytes and save \*/
	packuswb %mm4, %mm2
	movd %mm2, (%edi, %ecx, 4)

	incl %ecx
	js 1b

	LOOP_END
	LEAVE

SIZE(imlib_mmx_blend_rgb_to_rgb_cmod)

PR_(imlib_mmx_blend_rgb_to_rgba_cmod):
	ENTER

	pxor %mm4, %mm4
	LOAD_IMMQ(m0X000000, %mm5)
	LOAD_IMMQ(m00XXXXXX, %mm6)
	LOAD_IMMQ(c1, %mm7)
	CLEANUP_IMMQ_LOADS(3)

	LOOP_START
1:
	/*\ Load source and destination \*/
	LOAD1_CMOD_AFF
	movd (%edi, %ecx, 4), %mm2

	/*\ Get alpha from source and target, a = src + (255 - dest) \*/
	movq %mm2, %mm3
	pxor %mm6, %mm3
	paddusb %mm1, %mm3
	/*\ Unpack/copy to eight bytes \*/
	punpcklbw %mm3, %mm3
	punpckhwd %mm3, %mm3
	punpckhdq %mm3, %mm3
	psrlw $1, %mm3

	/*\ Unpack source and destination, bytes to words \*/
	punpcklbw %mm4, %mm1
	punpcklbw %mm4, %mm2

	/*\ Separate alpha channel \*/
	movq %mm1, %mm0
	pand %mm5, %mm0

	/*\ d = d + (a * ((s - d) + 0.5)) \*/
	psubw %mm2, %mm1
	psllw $1, %mm1
	paddw %mm7, %mm1	/*\ Roundoff \*/
	pmulhw %mm3, %mm1

	/*\ Replace alpha channel with separated out version in mm0 and add \*/
	pand %mm6, %mm1
	por %mm0, %mm1
	paddw %mm1, %mm2

	/*\ Pack into lower 4 bytes and save \*/
	packuswb %mm4, %mm2
	movd %mm2, (%edi, %ecx, 4)

	incl %ecx
	js 1b

	LOOP_END
	LEAVE

SIZE(imlib_mmx_blend_rgb_to_rgba_cmod)

PR_(imlib_mmx_copy_rgba_to_rgb_cmod):
	ENTER

	LOOP_START
1:
	movzbl (%esi, %ecx, 4), %eax
	movzbl bmap(%eax), %eax
	movb %al, (%edi, %ecx, 4)
	movzbl 1(%esi, %ecx, 4), %eax
	movzbl gmap(%eax), %eax
	movb %al, 1(%edi, %ecx, 4)
	movzbl 2(%esi, %ecx, 4), %eax
	movzbl rmap(%eax), %eax
	movb %al, 2(%edi, %ecx, 4)

	incl %ecx
	js 1b

	LOOP_END
	LEAVE

SIZE(imlib_mmx_copy_rgba_to_rgb_cmod)

PR_(imlib_mmx_copy_rgba_to_rgba_cmod):
	ENTER

	LOOP_START
1:
	movzbl (%esi, %ecx, 4), %eax
	movzbl bmap(%eax), %eax
	movb %al, (%edi, %ecx, 4)
	movzbl 1(%esi, %ecx, 4), %eax
	movzbl gmap(%eax), %eax
	movb %al, 1(%edi, %ecx, 4)
	movzbl 2(%esi, %ecx, 4), %eax
	movzbl rmap(%eax), %eax
	movb %al, 2(%edi, %ecx, 4)
	movzbl 3(%esi, %ecx, 4), %eax
	movzbl amap(%eax), %eax
	movb %al, 3(%edi, %ecx, 4)

	incl %ecx
	js 1b

	LOOP_END
	LEAVE

SIZE(imlib_mmx_copy_rgba_to_rgba_cmod)

PR_(imlib_mmx_copy_rgb_to_rgba_cmod):
	ENTER

	LOOP_START
1:
	movzbl (%esi, %ecx, 4), %eax
	movzbl bmap(%eax), %eax
	movb %al, (%edi, %ecx, 4)
	movzbl 1(%esi, %ecx, 4), %eax
	movzbl gmap(%eax), %eax
	movb %al, 1(%edi, %ecx, 4)
	movzbl 2(%esi, %ecx, 4), %eax
	movzbl rmap(%eax), %eax
	movb %al, 2(%edi, %ecx, 4)
	movb $0xff, 3(%edi, %ecx, 4)

	incl %ecx
	js 1b

	LOOP_END
	LEAVE

SIZE(imlib_mmx_copy_rgb_to_rgba_cmod)

PR_(imlib_mmx_add_blend_rgba_to_rgb_cmod):
	ENTER

	pxor %mm4, %mm4

	LOOP_START
1:
	/*\ Load source and destination \*/
	LOAD1_CMOD
	movd (%edi, %ecx, 4), %mm2

	/*\ Get alpha from source and unpack/copy to eight bytes \*/
	movq %mm1, %mm3
	punpcklbw %mm3, %mm3
	punpckhwd %mm3, %mm3
	punpckhdq %mm3, %mm3
	psrlw $1, %mm3

	psrlq $16, %mm3

	/*\ Unpack source and destination, bytes to words \*/
	punpcklbw %mm4, %mm1
	punpcklbw %mm4, %mm2

	/*\ d = d + (a * s) \*/
	psllw $1, %mm1
	pmulhw %mm3, %mm1
	paddw %mm1, %mm2

	/*\ Pack into lower 4 bytes and save \*/
	packuswb %mm4, %mm2
	movd %mm2, (%edi, %ecx, 4)
	
	incl %ecx
	js 1b

	LOOP_END
	LEAVE

SIZE(imlib_mmx_add_blend_rgba_to_rgb_cmod)

PR_(imlib_mmx_add_blend_rgba_to_rgba_cmod):
	ENTER

	pxor %mm4, %mm4
	LOAD_IMMQ(mVX000000, %mm5)
	LOAD_IMMQ(m00XXXXXX, %mm6)
	CLEANUP_IMMQ_LOADS(2)

	LOOP_START
1:
	/*\ Load source and destination \*/
	LOAD1_CMOD
	movd (%edi, %ecx, 4), %mm2

	/*\ Get alpha from source and target and unpack/copy to eight bytes \*/
	movq %mm2, %mm3
	pxor %mm6, %mm3
	paddusb %mm1, %mm3
	punpcklbw %mm3, %mm3
	punpckhwd %mm3, %mm3
	punpckhdq %mm3, %mm3
	psrlw $1, %mm3

	/*\ Make the alpha value that gets multiplied to the
	|*|  alpha channels 0x7fff, so the resulting alpha value is
	|*|  the sum of the source and destination alpha values.
	\*/
	por %mm5, %mm3

	/*\ Unpack source and destination, bytes to words \*/
	punpcklbw %mm4, %mm1
	punpcklbw %mm4, %mm2

	/*\ d = d + (a * s) \*/
	psllw $1, %mm1
	pmulhw %mm3, %mm1
	paddw %mm1, %mm2

	/*\ Pack into lower 4 bytes and save \*/
	packuswb %mm4, %mm2
	movd %mm2, (%edi, %ecx, 4)
	
	incl %ecx
	js 1b

	LOOP_END
	LEAVE

SIZE(imlib_mmx_add_blend_rgba_to_rgba_cmod)

PR_(imlib_mmx_add_blend_rgb_to_rgb_cmod):
	ENTER

	pxor %mm4, %mm4

	/*\ Load alpha beforehand, as it's always amap(0xff) \*/
	movzbl amap_ff, %eax
	movd %eax, %mm3
	punpcklbw %mm3, %mm3
	punpcklwd %mm3, %mm3
	punpckldq %mm3, %mm3
	psrlw $1, %mm3
	psrlq $16, %mm3

	LOOP_START
1:
	/*\ Load source and destination \*/
	LOAD1_CMOD_A00
	movd (%edi, %ecx, 4), %mm2

	/*\ Unpack source and destination, bytes to words \*/
	punpcklbw %mm4, %mm1
	punpcklbw %mm4, %mm2

	/*\ d = d + (a * s) \*/
	psllw $1, %mm1
	pmulhw %mm3, %mm1
	paddw %mm1, %mm2

	/*\ Pack into lower 4 bytes and save \*/
	packuswb %mm4, %mm2
	movd %mm2, (%edi, %ecx, 4)
	
	incl %ecx
	js 1b

	LOOP_END
	LEAVE

SIZE(imlib_mmx_add_blend_rgb_to_rgb_cmod)

PR_(imlib_mmx_add_blend_rgb_to_rgba_cmod):
	ENTER

	pxor %mm4, %mm4
	LOAD_IMMQ(mVX000000, %mm5)
	LOAD_IMMQ(m00XXXXXX, %mm6)
	CLEANUP_IMMQ_LOADS(2)

	LOOP_START
1:
	/*\ Load source and destination \*/
	LOAD1_CMOD_AFF
	movd (%edi, %ecx, 4), %mm2

	/*\ Get alpha from source and target and unpack/copy to eight bytes \*/
	movq %mm2, %mm3
	pxor %mm6, %mm3
	paddusb %mm1, %mm3
	punpcklbw %mm3, %mm3
	punpckhwd %mm3, %mm3
	punpckhdq %mm3, %mm3
	psrlw $1, %mm3

	/*\ Make the alpha value that gets multiplied to the
	|*|  alpha channels 0x7fff, so the resulting alpha value is
	|*|  the sum of the source and destination alpha values.
	\*/
	por %mm5, %mm3

	/*\ Unpack source and destination, bytes to words \*/
	punpcklbw %mm4, %mm1
	punpcklbw %mm4, %mm2

	/*\ d = d + (a * s) \*/
	psllw $1, %mm1
	pmulhw %mm3, %mm1
	paddw %mm1, %mm2

	/*\ Pack into lower 4 bytes and save \*/
	packuswb %mm4, %mm2
	movd %mm2, (%edi, %ecx, 4)
	
	incl %ecx
	js 1b

	LOOP_END
	LEAVE

SIZE(imlib_mmx_add_blend_rgb_to_rgba_cmod)

PR_(imlib_mmx_add_copy_rgba_to_rgb_cmod):
	ENTER

	LOAD_IMMQ(m0XXX0XXX, %mm5)
	CLEANUP_IMMQ_LOADS(1)

	subl $4, %esi
	subl $4, %edi

	LOOP_START
	incl %ecx
	jz 2f
1:
	/*\ Load source and destination \*/
	LOAD2_CMOD
	movq (%edi, %ecx, 4), %mm2

	/*\ Clear alpha channel of source \*/
	pand %mm5, %mm1

	/*\ d = d + s, unsigned saturation, and save \*/
	paddusb %mm1, %mm2
	movq %mm2, (%edi, %ecx, 4)
	
	addl $2, %ecx
	js 1b
	jnz 3f
2:
	LOAD1_CMOD
	movd (%edi), %mm2
	pand %mm5, %mm1
	paddusb %mm1, %mm2
	movd %mm2, (%edi)
3:
	LOOP_END
	LEAVE

SIZE(imlib_mmx_add_copy_rgba_to_rgb_cmod)

PR_(imlib_mmx_add_copy_rgba_to_rgba_cmod):
	ENTER

	subl $4, %esi
	subl $4, %edi

	LOOP_START
	incl %ecx
	jz 2f
1:
	/*\ Load source and destination \*/
	LOAD2_CMOD
	movq (%edi, %ecx, 4), %mm2

	/*\ d = d + s, unsigned saturation, and save \*/
	paddusb %mm1, %mm2
	movq %mm2, (%edi, %ecx, 4)
	
	addl $2, %ecx
	js 1b
	jnz 3f
2:
	LOAD1_CMOD
	movd (%edi), %mm2
	paddusb %mm1, %mm2
	movd %mm2, (%edi)
3:
	LOOP_END
	LEAVE

SIZE(imlib_mmx_add_copy_rgba_to_rgba_cmod)

PR_(imlib_mmx_add_copy_rgb_to_rgba_cmod):
	ENTER

	subl $4, %esi
	subl $4, %edi

	LOOP_START
	incl %ecx
	jz 2f
1:
	/*\ Load source and destination \*/
	LOAD2_CMOD_AFF
	movq (%edi, %ecx, 4), %mm2

	/*\ d = d + s, unsigned saturation, and save \*/
	paddusb %mm1, %mm2
	movq %mm2, (%edi, %ecx, 4)
	
	addl $2, %ecx
	js 1b
	jnz 3f
2:
	LOAD1_CMOD_AFF
	movd (%edi), %mm2
	paddusb %mm1, %mm2
	movd %mm2, (%edi)
3:
	LOOP_END
	LEAVE

SIZE(imlib_mmx_add_copy_rgb_to_rgba_cmod)

PR_(imlib_mmx_subtract_blend_rgba_to_rgb_cmod):
	ENTER

	pxor %mm4, %mm4

	LOOP_START
1:
	/*\ Load source and destination \*/
	LOAD1_CMOD
	movd (%edi, %ecx, 4), %mm2

	/*\ Get alpha from source and unpack/copy to eight bytes \*/
	movq %mm1, %mm3
	punpcklbw %mm3, %mm3
	punpckhwd %mm3, %mm3
	punpckhdq %mm3, %mm3
	psrlw $1, %mm3

	psrlq $16, %mm3

	/*\ Unpack source and destination, bytes to words \*/
	punpcklbw %mm4, %mm1
	punpcklbw %mm4, %mm2

	/*\ d = d - (a * s) \*/
	psllw $1, %mm1
	pmulhw %mm3, %mm1
	psubw %mm1, %mm2

	/*\ Pack into lower 4 bytes and save \*/
	packuswb %mm4, %mm2
	movd %mm2, (%edi, %ecx, 4)
	
	incl %ecx
	js 1b

	LOOP_END
	LEAVE

SIZE(imlib_mmx_subtract_blend_rgba_to_rgb_cmod)

PR_(imlib_mmx_subtract_blend_rgba_to_rgba_cmod):
	ENTER

	pxor %mm4, %mm4
	LOAD_IMMQ(mV0000000, %mm5)
	LOAD_IMMQ(m00XXXXXX, %mm6)
	CLEANUP_IMMQ_LOADS(2)

	LOOP_START
1:
	/*\ Load source and destination \*/
	LOAD1_CMOD
	movd (%edi, %ecx, 4), %mm2

	/*\ Get alpha from source and target and unpack/copy to eight bytes \*/
	movq %mm2, %mm3
	pxor %mm6, %mm3
	paddusb %mm1, %mm3
	punpcklbw %mm3, %mm3
	punpckhwd %mm3, %mm3
	punpckhdq %mm3, %mm3
	psrlw $1, %mm3

	/*\ Make alpha value that gets multiplied with alpha channel
	|*| 0x8000, (-1.0), so that the alpha result is s + d
	\*/
	psrlq $16, %mm3
	por %mm5, %mm3

	/*\ Unpack source and destination, bytes to words \*/
	punpcklbw %mm4, %mm1
	punpcklbw %mm4, %mm2

	/*\ d = d - (a * s) \*/
	psllw $1, %mm1
	pmulhw %mm3, %mm1
	psubw %mm1, %mm2

	/*\ Pack into lower 4 bytes and save \*/
	packuswb %mm4, %mm2
	movd %mm2, (%edi, %ecx, 4)
	
	incl %ecx
	js 1b

	LOOP_END
	LEAVE

SIZE(imlib_mmx_subtract_blend_rgba_to_rgba_cmod)

PR_(imlib_mmx_subtract_blend_rgb_to_rgb_cmod):
	ENTER

	pxor %mm4, %mm4

	/*\ Load alpha beforehand, as it's always amap(0xff) \*/
	movzbl amap_ff, %eax
	movd %eax, %mm3
	punpcklbw %mm3, %mm3
	punpcklwd %mm3, %mm3
	punpckldq %mm3, %mm3
	psrlw $1, %mm3
	psrlq $16, %mm3

	LOOP_START
1:
	/*\ Load source and destination \*/
	LOAD1_CMOD_A00
	movd (%edi, %ecx, 4), %mm2

	/*\ Unpack source and destination, bytes to words \*/
	punpcklbw %mm4, %mm1
	punpcklbw %mm4, %mm2

	/*\ d = d - (a * s) \*/
	psllw $1, %mm1
	pmulhw %mm3, %mm1
	psubw %mm1, %mm2

	/*\ Pack into lower 4 bytes and save \*/
	packuswb %mm4, %mm2
	movd %mm2, (%edi, %ecx, 4)
	
	incl %ecx
	js 1b

	LOOP_END
	LEAVE

SIZE(imlib_mmx_subtract_blend_rgb_to_rgb_cmod)

PR_(imlib_mmx_subtract_blend_rgb_to_rgba_cmod):
	ENTER

	pxor %mm4, %mm4
	LOAD_IMMQ(mV0000000, %mm5)
	LOAD_IMMQ(m00XXXXXX, %mm6)
	CLEANUP_IMMQ_LOADS(2)

	LOOP_START
1:
	/*\ Load source and destination \*/
	LOAD1_CMOD_AFF
	movd (%edi, %ecx, 4), %mm2

	/*\ Get alpha from source and target and unpack/copy to eight bytes \*/
	movq %mm2, %mm3
	pxor %mm6, %mm3
	paddusb %mm1, %mm3
	punpcklbw %mm3, %mm3
	punpckhwd %mm3, %mm3
	punpckhdq %mm3, %mm3
	psrlw $1, %mm3

	/*\ Make alpha value that gets multiplied with alpha channel
	|*| 0x8000, (-1.0), so that the alpha result is s + d
	\*/
	psrlq $16, %mm3
	por %mm5, %mm3

	/*\ Unpack source and destination, bytes to words \*/
	punpcklbw %mm4, %mm1
	punpcklbw %mm4, %mm2

	/*\ d = d - (a * s) \*/
	psllw $1, %mm1
	pmulhw %mm3, %mm1
	psubw %mm1, %mm2

	/*\ Pack into lower 4 bytes and save \*/
	packuswb %mm4, %mm2
	movd %mm2, (%edi, %ecx, 4)
	
	incl %ecx
	js 1b

	LOOP_END
	LEAVE

SIZE(imlib_mmx_subtract_blend_rgb_to_rgba_cmod)

PR_(imlib_mmx_subtract_copy_rgba_to_rgb_cmod):
	ENTER

	LOAD_IMMQ(m0XXX0XXX, %mm5)
	CLEANUP_IMMQ_LOADS(1)

	subl $4, %esi
	subl $4, %edi

	LOOP_START
	incl %ecx
	jz 2f
1:
	/*\ Load source and destination \*/
	LOAD2_CMOD
	movq (%edi, %ecx, 4), %mm2

	/*\ Clear alpha channel of source \*/
	pand %mm5, %mm1

	/*\ d = d - s, unsigned saturation, and save \*/
	psubusb %mm1, %mm2
	movq %mm2, (%edi, %ecx, 4)
	
	addl $2, %ecx
	js 1b
	jnz 3f
2:
	LOAD1_CMOD
	movd (%edi), %mm2
	pand %mm5, %mm1
	psubusb %mm1, %mm2
	movd %mm2, (%edi)
3:
	LOOP_END
	LEAVE

SIZE(imlib_mmx_subtract_copy_rgba_to_rgb_cmod)

PR_(imlib_mmx_subtract_copy_rgba_to_rgba_cmod):
	ENTER

	LOAD_IMMQ(mX000X000, %mm5)
	CLEANUP_IMMQ_LOADS(1)

	subl $4, %esi
	subl $4, %edi

	LOOP_START
	incl %ecx
	jz 2f
1:
	/*\ Load source and destination \*/
	LOAD2_CMOD
	movq (%edi, %ecx, 4), %mm2

	/*\ Negate destination alphas \*/
	pxor %mm5, %mm2

	/*\ d = d - s, unsigned saturation, and save \*/
	psubusb %mm1, %mm2

	/*\ Negate result alphas \*/
	pxor %mm5, %mm2
	movq %mm2, (%edi, %ecx, 4)
	
	addl $2, %ecx
	js 1b
	jnz 3f
2:
	LOAD1_CMOD
	movd (%edi), %mm2
	pxor %mm5, %mm2
	psubusb %mm1, %mm2
	pxor %mm5, %mm2
	movd %mm2, (%edi)
3:
	LOOP_END
	LEAVE

SIZE(imlib_mmx_subtract_copy_rgba_to_rgba_cmod)

PR_(imlib_mmx_subtract_copy_rgb_to_rgba_cmod):
	ENTER

	LOAD_IMMQ(mX000X000, %mm5)
	CLEANUP_IMMQ_LOADS(1)

	subl $4, %esi
	subl $4, %edi

	LOOP_START
	incl %ecx
	jz 2f
1:
	/*\ Load source and destination \*/
	LOAD2_CMOD_AFF
	movq (%edi, %ecx, 4), %mm2
	pxor %mm5, %mm2

	/*\ d = d - s, unsigned saturation, and save \*/
	psubusb %mm1, %mm2
	pxor %mm5, %mm2
	movq %mm2, (%edi, %ecx, 4)
	
	addl $2, %ecx
	js 1b
	jnz 3f
2:
	LOAD1_CMOD_AFF
	movd (%edi), %mm2
	pxor %mm5, %mm2
	psubusb %mm1, %mm2
	pxor %mm5, %mm2
	movd %mm2, (%edi)
3:
	LOOP_END
	LEAVE

SIZE(imlib_mmx_subtract_copy_rgb_to_rgba_cmod)

PR_(imlib_mmx_reshade_blend_rgba_to_rgb_cmod):
	ENTER

	pxor %mm4, %mm4
	LOAD_IMMQ(m000V0V0V, %mm6)
	CLEANUP_IMMQ_LOADS(1)

	LOOP_START
1:
	/*\ Load source and destination \*/
	LOAD1_CMOD
	movd (%edi, %ecx, 4), %mm2

	/*\ Get alpha from source and unpack/copy to eight bytes \*/
	movq %mm1, %mm3
	punpcklbw %mm3, %mm3
	punpckhwd %mm3, %mm3
	punpckhdq %mm3, %mm3
	psrlw $1, %mm3

	psrlq $16, %mm3

	/*\ Unpack source and destination, bytes to words \*/
	punpcklbw %mm4, %mm1
	punpcklbw %mm4, %mm2

	/*\ d = d + (2 * a * (s - 127)) \*/
	psubw %mm6, %mm1
	psllw $2, %mm1
	pmulhw %mm3, %mm1
	paddw %mm1, %mm2

	/*\ Pack into lower 4 bytes and save \*/
	packuswb %mm4, %mm2
	movd %mm2, (%edi, %ecx, 4)
	
	incl %ecx
	js 1b

	LOOP_END
	LEAVE

SIZE(imlib_mmx_reshade_blend_rgba_to_rgb_cmod)

PR_(imlib_mmx_reshade_blend_rgba_to_rgba_cmod):
	ENTER

	pxor %mm4, %mm4
	LOAD_IMMQ(mI0000000, %mm5)
	LOAD_IMMQ(m000V0V0V, %mm6)
	LOAD_IMMQ(m00XXXXXX, %mm7)
	CLEANUP_IMMQ_LOADS(3)

	LOOP_START
1:
	/*\ Load source and destination \*/
	LOAD1_CMOD
	movd (%edi, %ecx, 4), %mm2

	/*\ Get alpha from source and target and unpack/copy to eight bytes \*/
	movq %mm2, %mm3
	pxor %mm7, %mm3
	paddusb %mm1, %mm3
	punpcklbw %mm3, %mm3
	punpckhwd %mm3, %mm3
	punpckhdq %mm3, %mm3
	psrlw $1, %mm3

	/*\ Make the alpha value that gets multiplied to the
	|*|  alpha channels 0x4000 (0.5), so the resulting alpha value is
	|*|  the sum of the source and destination alpha values.
	\*/
	psrlq $16, %mm3
	por %mm5, %mm3

	/*\ Unpack source and destination, bytes to words \*/
	punpcklbw %mm4, %mm1
	punpcklbw %mm4, %mm2

	/*\ d = d + (2 * a * (s - 127)), (alpha channel: d = d + (2 * 0.5 * (s - 0)) ) \*/
	psubw %mm6, %mm1
	psllw $2, %mm1
	pmulhw %mm3, %mm1
	paddw %mm1, %mm2

	/*\ Pack into lower 4 bytes and save \*/
	packuswb %mm4, %mm2
	movd %mm2, (%edi, %ecx, 4)
	
	incl %ecx
	js 1b

	LOOP_END
	LEAVE

SIZE(imlib_mmx_reshade_blend_rgba_to_rgba_cmod)

PR_(imlib_mmx_reshade_blend_rgb_to_rgb_cmod):
	ENTER

	pxor %mm4, %mm4
	LOAD_IMMQ(m000V0V0V, %mm6)
	CLEANUP_IMMQ_LOADS(1)

	/*\ Load alpha beforehand, as it's always amap(0xff) \*/
	movzbl amap_ff, %eax
	movd %eax, %mm3
	punpcklbw %mm3, %mm3
	punpcklwd %mm3, %mm3
	punpckldq %mm3, %mm3
	psrlw $1, %mm3
	psrlq $16, %mm3

	LOOP_START
1:
	/*\ Load source and destination \*/
	LOAD1_CMOD_A00
	movd (%edi, %ecx, 4), %mm2

	/*\ Unpack source and destination, bytes to words \*/
	punpcklbw %mm4, %mm1
	punpcklbw %mm4, %mm2

	/*\ d = d + (2 * a * (s - 127)) \*/
	psubw %mm6, %mm1
	psllw $2, %mm1
	pmulhw %mm3, %mm1
	paddw %mm1, %mm2

	/*\ Pack into lower 4 bytes and save \*/
	packuswb %mm4, %mm2
	movd %mm2, (%edi, %ecx, 4)
	
	incl %ecx
	js 1b

	LOOP_END
	LEAVE

SIZE(imlib_mmx_reshade_blend_rgb_to_rgb_cmod)

PR_(imlib_mmx_reshade_blend_rgb_to_rgba_cmod):
	ENTER

	pxor %mm4, %mm4
	LOAD_IMMQ(mI0000000, %mm5)
	LOAD_IMMQ(m000V0V0V, %mm6)
	LOAD_IMMQ(m00XXXXXX, %mm7)
	CLEANUP_IMMQ_LOADS(3)

	LOOP_START
1:
	/*\ Load source and destination \*/
	LOAD1_CMOD_AFF
	movd (%edi, %ecx, 4), %mm2

	/*\ Get alpha from source and target and unpack/copy to eight bytes \*/
	movq %mm2, %mm3
	pxor %mm7, %mm3
	paddusb %mm1, %mm3
	punpcklbw %mm3, %mm3
	punpckhwd %mm3, %mm3
	punpckhdq %mm3, %mm3
	psrlw $1, %mm3

	/*\ Make the alpha value that gets multiplied to the
	|*|  alpha channels 0x4000 (0.5), so the resulting alpha value is
	|*|  the sum of the source and destination alpha values.
	\*/
	psrlq $16, %mm3
	por %mm5, %mm3

	/*\ Unpack source and destination, bytes to words \*/
	punpcklbw %mm4, %mm1
	punpcklbw %mm4, %mm2

	/*\ d = d + (2 * a * (s - 127)), (alpha channel: d = d + (2 * 0.5 * (s - 0)) ) \*/
	psubw %mm6, %mm1
	psllw $2, %mm1
	pmulhw %mm3, %mm1
	paddw %mm1, %mm2

	/*\ Pack into lower 4 bytes and save \*/
	packuswb %mm4, %mm2
	movd %mm2, (%edi, %ecx, 4)
	
	incl %ecx
	js 1b

	LOOP_END
	LEAVE

SIZE(imlib_mmx_reshade_blend_rgb_to_rgba_cmod)

PR_(imlib_mmx_reshade_copy_rgba_to_rgb_cmod):
	ENTER

	pxor %mm4, %mm4
	LOAD_IMMQ(m0XXX0XXX, %mm5)
	LOAD_IMMQ(m0VVV0VVV, %mm6)
	CLEANUP_IMMQ_LOADS(2)

	subl $4, %esi
	subl $4, %edi

	LOOP_START
	incl %ecx
	jz 2f
1:
	/*\ Load source and destination \*/
	LOAD2_CMOD
	movq (%edi, %ecx, 4), %mm2

	/*\ To take advantage of saturation and be able to do 8 bytes
	|*|  at a time, we divide reshading into two separate steps:
	|*|  adding values above 128, and subtracting values below 128
	|*| These values go into %mm1 and %mm3 respectively
	|*| - %mm1 becomes (2 * (s - 127))
	|*| - %mm3 becomes (2 * (255 - (127 + s))) = (2 * (128 - s))
	\*/
	movq %mm1, %mm3
	psubusb %mm6, %mm1
	paddusb %mm1, %mm1
	paddusb %mm6, %mm3
	pxor %mm5, %mm3
	paddusb %mm3, %mm3

	/*\ Clear alpha channel of s1 and s2 \*/
	pand %mm5, %mm1
	pand %mm5, %mm3

	/*\ d = d + s1 - s2, unsigned saturation, and save \*/
	paddusb %mm1, %mm2
	psubusb %mm3, %mm2
	movq %mm2, (%edi, %ecx, 4)
	
	addl $2, %ecx
	js 1b
	jnz 3f
2:
	LOAD1_CMOD
	movd (%edi), %mm2
	movq %mm1, %mm3
	psubusb %mm6, %mm1
	paddusb %mm1, %mm1
	paddusb %mm6, %mm3
	pxor %mm5, %mm3
	paddusb %mm3, %mm3
	pand %mm5, %mm1
	pand %mm5, %mm3
	paddusb %mm1, %mm2
	psubusb %mm3, %mm2
	movd %mm2, (%edi)
3:
	LOOP_END
	LEAVE

SIZE(imlib_mmx_reshade_copy_rgba_to_rgb_cmod)

PR_(imlib_mmx_reshade_copy_rgba_to_rgba_cmod):
	ENTER

	pxor %mm4, %mm4
	LOAD_IMMQ(m0XXX0XXX, %mm5)
	LOAD_IMMQ(m0VVV0VVV, %mm6)
	CLEANUP_IMMQ_LOADS(2)

	subl $4, %esi
	subl $4, %edi

	LOOP_START
	incl %ecx
	jz 2f
1:
	/*\ Load source and destination \*/
	LOAD2_CMOD
	movq (%edi, %ecx, 4), %mm2

	/*\ This time, the alpha channels have to be added.
	|*| For that, the alpha channel of %mm1 should remain
	|*|  the same.  This is done by subtracting 0 from the
	|*|  alpha channel, and then doing the *2 via a separate
	|*|  register, clearing its alpha channel first.
	\*/
	movq %mm1, %mm3
	psubusb %mm6, %mm1
	movq %mm1, %mm0
	pand %mm5, %mm0
	paddusb %mm0, %mm1
	paddusb %mm6, %mm3
	pxor %mm5, %mm3
	paddusb %mm3, %mm3

	/*\ Clear alpha channel of s2 \*/
	pand %mm5, %mm3

	/*\ d = d + s1 - s2, unsigned saturation, and save \*/
	paddusb %mm1, %mm2
	psubusb %mm3, %mm2
	movq %mm2, (%edi, %ecx, 4)
	
	addl $2, %ecx
	js 1b
	jnz 3f
2:
	LOAD1_CMOD
	movd (%edi), %mm2
	movq %mm1, %mm3
	psubusb %mm6, %mm1
	movq %mm1, %mm0
	pand %mm5, %mm0
	paddusb %mm0, %mm1
	paddusb %mm6, %mm3
	pxor %mm5, %mm3
	paddusb %mm3, %mm3
	pand %mm5, %mm3
	paddusb %mm1, %mm2
	psubusb %mm3, %mm2
	movd %mm2, (%edi)
3:
	LOOP_END
	LEAVE

SIZE(imlib_mmx_reshade_copy_rgba_to_rgba_cmod)

PR_(imlib_mmx_reshade_copy_rgb_to_rgba_cmod):
	ENTER

	pxor %mm4, %mm4
	LOAD_IMMQ(m0XXX0XXX, %mm5)
	LOAD_IMMQ(m0VVV0VVV, %mm6)
	CLEANUP_IMMQ_LOADS(2)

	subl $4, %esi
	subl $4, %edi

	LOOP_START
	incl %ecx
	jz 2f
1:
	/*\ Load source and destination \*/
	LOAD2_CMOD_AFF
	movq (%edi, %ecx, 4), %mm2

	movq %mm1, %mm3
	psubusb %mm6, %mm1
	movq %mm1, %mm0
	pand %mm5, %mm0
	paddusb %mm0, %mm1
	paddusb %mm6, %mm3
	pxor %mm5, %mm3
	paddusb %mm3, %mm3

	/*\ Clear alpha channel of s2 \*/
	pand %mm5, %mm3

	/*\ d = d + s1 - s2, unsigned saturation, and save \*/
	paddusb %mm1, %mm2
	psubusb %mm3, %mm2
	movq %mm2, (%edi, %ecx, 4)
	
	addl $2, %ecx
	js 1b
	jnz 3f
2:
	LOAD1_CMOD_AFF
	movd (%edi), %mm2
	movq %mm1, %mm3
	psubusb %mm6, %mm1
	movq %mm1, %mm0
	pand %mm5, %mm0
	paddusb %mm0, %mm1
	paddusb %mm6, %mm3
	pxor %mm5, %mm3
	paddusb %mm3, %mm3
	pand %mm5, %mm3
	paddusb %mm1, %mm2
	psubusb %mm3, %mm2
	movd %mm2, (%edi)
3:
	LOOP_END
	LEAVE

SIZE(imlib_mmx_reshade_copy_rgb_to_rgba_cmod)

#endif

#ifdef __ELF__
.section .note.GNU-stack,"",@progbits
#endif
